﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using IndicoInterface;
using DTBuilderLib;
using DTBuilderLib.VisualHierarchyClasses;
using IndicoInterface.SimpleAgendaDataModel;
using Deep_Talk_Converter.Properties;
using System.IO;
using Utilities;

namespace Deep_Talk_Converter.RenderWorkItems
{
    /// <summary>
    /// Do the actual work of rendering a meeting locally. We don't care about the thread we are on...
    /// </summary>
    class RenderMeetingLocally
    {
        private string _url;

        public RenderMeetingLocally(string url)
        {
            _url = url;
        }

        public DirectoryInfo ProjectDir { get; private set; }

        public string Title { get; private set; }

        public delegate void MeetingNameCallback(string meetingName);

        public delegate void ProgressMessageCallback (string message);

        public delegate void RenderDoneCallback(bool ok, string message, string uri);

        /// <summary>
        /// Called when the meeting name is known.
        /// </summary>
        public event MeetingNameCallback MeetingNameKnown;

        /// <summary>
        /// Called when we are notifying people of progress.
        /// </summary>
        public event ProgressMessageCallback ProgressMessage;

        public event RenderDoneCallback RenderDone;

        /// <summary>
        /// Returns a temp directory. Uses default system temp directory unless something else has been specified.
        /// </summary>
        /// <param name="taskName"></param>
        /// <returns></returns>
        private string GetTempDirectory(string taskName)
        {
            string b;
            if (Settings.Default.TempPath == "")
            {
                b = Path.GetTempPath();
            }
            else
            {
                b = Settings.Default.TempPath;
            }

            return b + "\\" + taskName;
        }

        /// <summary>
        /// Start the talk render -- download it first to our local disk.
        /// </summary>
        public void Render()
        {
            try
            {
                ///
                /// Get the agenda downloaded!
                /// 

                SendProgressMessage("Downloading the agenda");
                AgendaInfo a = new AgendaInfo(_url);
                var agendaData = a.GetNormalizedConferenceData();

                SendMeetingKnown(agendaData.Title);
                Title = agendaData.Title;

                ///
                /// Now, render the jpeg's
                /// 

                SendProgressMessage("Preparing to download meeting slides");
                JobDownloader downloader = new JobDownloader();
                downloader.FileDownloadLocation = GetTempDirectory("Agenda Downloads");
                downloader.StartMeetingDownload(agendaData,
                    (Meeting meeting, Session session, Talk talk, float percent) => SendProgressMessage("Downloading " + talk.Title + " - " + percent.ToString("F1") + "%"),
                    (Meeting meeting) => ThreadPool.QueueUserWorkItem(obj => CompleteRender((Meeting)obj), meeting));
            }
            catch (Exception e)
            {
                SendRenderDone(false, e.ToString(), "");
            }
        }

        /// <summary>
        /// The job download is done. Now we continue on.
        /// </summary>
        /// <returns></returns>
        private void CompleteRender(Meeting meeting)
        {
            try
            {
                ///
                /// Build the output directory
                /// 

                string baseBuild = Settings.Default.JobOutput + "\\" + meeting.StartDate.ToString("yyyy-MM-dd") + " - " + NormalizeForDirnames(meeting.Title);

                ///
                /// Render all the JPEG images
                /// 

                SendProgressMessage("Rendering the meeting to JPEG images");
                JPEGRender rj = new JPEGRender();
                rj.DotsPerInch = Settings.Default.DPI;
                var slides = rj.RenderMeeting(meeting);

                ///
                /// Create the deep zoom dude so we can see if we've already rendered this guy.
                /// 

                SendProgressMessage("Buiding the DeepZoom Image...");
                DeepZoomBuilder dz = new DeepZoomBuilder();
                dz.BuildDirectory = baseBuild;

                if (!dz.MeetingAlreadyRendered("meeting"))
                {

                    SendProgressMessage("Creating a visual scene of the meeting");
                    LayoutBuilder bld = new LayoutBuilder();
                    bld.DPI = Settings.Default.DPI;
                    bld.ImageCreationPath = GetTempDirectory("Layout Images");
                    var scene = bld.BuildVisualTreeForAMeeting(meeting, slides);

                    SendProgressMessage("Creating DeepZoom image");
                    dz.RenderVisual("meeting", scene);
                }

                ///
                /// Finally, move over the various files we need to use this thing.
                /// 

                DirectoryInfo dest = new DirectoryInfo(dz.BuildDirectory);
                FileInfo startPage = WebSiteBuilder.CreateWebSite(dest, meeting.Title + " - DeepTalk");
                ProjectDir = dest;

                ///
                /// Create a short cut to the local web server so the user can view the various items.
                /// 

                FileInfo shortcutFile = new FileInfo(dest.FullName + "\\Conference Viewer.lnk");
                using (ShellLinkUtil.ShellLink link = new ShellLinkUtil.ShellLink())
                {
                    link.Target = ExternalToolLocations.LocationWebViewer;
                    link.Arguments = "\"" + dest.FullName + "\"";
                    link.WorkingDirectory = dest.FullName;
                    link.Description = "View a rendered conference by starting a local web server and web browser";
                    link.DisplayMode = ShellLinkUtil.ShellLink.LinkDisplayMode.edmMinimized;

                    link.Save(shortcutFile.FullName);
                }

                ///
                /// Done!
                /// 

                SendRenderDone(true, "Render finished ok!", shortcutFile.FullName);
            }
            catch (Exception e)
            {
                Logger.LogErrorMessage("GUIException", "Error: " + e.ToString() + " - " + e.StackTrace);
                SendRenderDone(false, e.ToString(), "");
            }
        }

        /// <summary>
        /// Cleans out a directory.
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private string NormalizeForDirnames(string dirname)
        {
            char[] badchars = Path.GetInvalidPathChars();
            int loc = dirname.IndexOfAny(badchars);
            while (loc >= 0)
            {
                dirname = dirname.Replace(dirname[loc], ' ');
            }
            dirname = dirname.Replace(':', ' ');
            return dirname.Trim();
        }

        private void SendProgressMessage(string p)
        {
            if (ProgressMessage != null)
            {
                ProgressMessage(p);
            }
        }

        private void SendMeetingKnown(string p)
        {
            if (MeetingNameKnown != null)
            {
                MeetingNameKnown(p);
            }
        }

        private void SendRenderDone(bool ok, string message, string uri)
        {
            if (RenderDone != null)
            {
                RenderDone(ok, message, uri);
            }
        }
    }
}
